package cn.easier.activity.console.quartz;

import cn.easier.activity.console.entity.LogRestore;
import cn.easier.activity.console.entity.LogsCount;
import cn.easier.activity.console.repository.ActivityInfoRepository;
import cn.easier.activity.console.repository.ActivityRecordStatisticsRepository;
import cn.easier.activity.console.repository.LogRestoreRepository;
import cn.easier.activity.console.repository.LogsCountRepository;
import cn.easier.activity.console.utils.CastEntityConvert;
import cn.easier.activity.web.entity.ActivityInfo;
import cn.easier.activity.web.entity.ActivityRecord;
import cn.easier.activity.web.entity.PrizeType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.text.ParseException;
import java.util.*;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lixiaopeng
 */
@Component
public class LogsRestore {

    private static Logger log = LoggerFactory.getLogger(LogsRestore.class);

    @Resource
    private LogRestoreRepository logRestoreRepository;

    @Resource
    private LogsCountRepository logsCountRepository;

    @Value("${metadata.log-resource.log-path}")
    public String path;

    @Resource
    private ActivityInfoRepository activityInfoRepository;

    @Resource
    private ActivityRecordStatisticsRepository recordRepository;

    private Map<String, String> activityInfoMap;// 活动信息表

    void restoreLog() {
        String logDay;
        File[] dayListLog;
        File fromLog;
        Reader reader = null;
        BufferedReader br = null;
        LogRestore logRestore;
        String str;
        File file = new File(path);
        logRestoreRepository.deleteAll();
        log.info("restoreLog delete success");
        String[] split;
        String jsessionid;
        String activityId;
        String lottery;
        String consumeScore;
        if (file.isDirectory()) {
            File[] listFiles = file.listFiles();
            for (File dayFolder : listFiles != null ? listFiles : new File[0]) {// 遍历天文件夹
                String dayFolderPath = dayFolder.getPath();
                log.info("restoreLog 文件夹名称=>{}", dayFolderPath);
                if (dayFolderPath.contains("/")) {
                    logDay = dayFolderPath.substring(dayFolderPath.lastIndexOf("/") + 1);
                } else {
                    logDay = dayFolderPath.substring(dayFolderPath.lastIndexOf("\\") + 1);
                }
                // 根据logDay从PvUvCount查询,如果不为空执行continue,不再读取,直接跳过读取未被读取的文件
                List<LogsCount> list = logsCountRepository.findByDay(logDay);
                if (list.size() > 0) {
                    continue;
                }
                if (dayFolder.isDirectory()) {
                    dayListLog = dayFolder.listFiles();
                    for (File listLog : dayListLog != null ? dayListLog : new File[0]) {// 遍历天文件夹下的日志文件
                        fromLog = new File(String.valueOf(listLog));
                        try {
                            reader = new FileReader(fromLog);
                            br = new BufferedReader(reader);
                            while ((str = br.readLine()) != null) {
                                if (str.contains("内部统计")) {
                                    split = str.split("\\|");
                                    jsessionid = split[1];
                                    activityId = split[3].split("=")[1];
                                    if (!activityInfoMap.containsKey(activityId)) {
                                        // 活动不存在，无效数据
                                        continue;
                                    }
                                    lottery = split[4];
                                    consumeScore = split[5].split("=")[1];
                                    logRestore = new LogRestore(logDay, jsessionid, activityId, lottery, Long.valueOf(consumeScore));
                                    logRestoreRepository.save(logRestore);
                                }
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        } finally {// 4.关闭流
                            try {
                                if (br != null) {
                                    br.close();
                                }
                                if (reader != null) {
                                    reader.close();
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
        log.info("restoreLog success");
    }

    void LogsCount() {
        long startTime = System.currentTimeMillis();
        String activityName;
        List<LogRestore> listActivityId;
        List<LogRestore> listDay;
        try {
            List<LogRestore> allLogs = logRestoreRepository.findAll();
            log.info("查询的数据条数=>{}", allLogs.size());
            listActivityId = allLogs.stream().filter(CastEntityConvert.distinctByKey(LogRestore::getActivityId))
                    .collect(Collectors.toList());// 对活动id去重
            log.info("对活动id去重后的数据条数=>{}", listActivityId.size());
            for (LogRestore idObj : listActivityId) {// 对去重的活动id进行遍历
                String activityId = idObj.getActivityId();
                activityName = activityInfoMap.get(activityId);
                listDay = allLogs.stream().filter(k -> k.getActivityId().equals(activityId)).filter(CastEntityConvert.distinctByKey(LogRestore::getAddDay)).collect(Collectors.toList());// 根据活动id对日期进行去重
                for (LogRestore day : listDay) {// 遍历去重的日期
                    String addDay = day.getAddDay();
                    long pv = allLogs.stream().filter(k -> k.getActivityId().equals(activityId)).filter(k -> k.getAddDay().equals(addDay)).count();
                    long uv = allLogs.stream().filter(k -> k.getActivityId().equals(activityId)).filter(k -> k.getAddDay().equals(addDay)).filter(CastEntityConvert.distinctByKey(LogRestore::getJsessionid)).count();
                    LogsCount logsCount = new LogsCount();
                    logsCount.setPv(pv);
                    logsCount.setUv(uv);
                    logsCount.setDay(addDay);
                    logsCount.setActivityId(activityId);
                    logsCount.setActivityName(activityName);
                    updateActivityData(logsCount);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("LogsCount success, time usage:{}ms", System.currentTimeMillis() - startTime);
    }

    /**
     * 查询指定天的记录
     */
    private void updateActivityData(LogsCount logsCountInDay) {
        String activityId = logsCountInDay.getActivityId();
        List<LogsCount> logsCountList = logsCountRepository.findByActivityIdAndDayIsNull(activityId);
        LogsCount countForActivity;
        if (CollectionUtils.isEmpty(logsCountList)) {
            countForActivity = new LogsCount();
            countForActivity.setActivityId(activityId);
            countForActivity.setActivityName(logsCountInDay.getActivityName());
            countForActivity.setDay(null);
            countForActivity.setPv(0L);
            countForActivity.setUv(0L);
            countForActivity.setTotalTimes(0L);
            countForActivity.setTotalPeople(0L);
            countForActivity.setConsumeScore(0L);
        } else {
            countForActivity = logsCountList.get(0);
        }
        String day = logsCountInDay.getDay();
        List<ActivityRecord> recordList = new ArrayList<>();
        try {
            Date beginDate = DateUtils.parseDate(day + " 00:00:00", "yyyy-MM-dd HH:mm:ss");
            Date endDate = DateUtils.parseDate(day + " 23:59:59", "yyyy-MM-dd HH:mm:ss");
            recordList = recordRepository.findByActivityIdAndCreateDateBetween(Integer.valueOf(activityId), beginDate, endDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Supplier<Stream<ActivityRecord>> supplier = recordList::stream;
        // 活动参与次数
        long totalTimes = supplier.get().count();
        logsCountInDay.setTotalTimes(totalTimes);
        countForActivity.setTotalTimes(countForActivity.getTotalTimes() + totalTimes);
        // 活动参与人数
        long totalPeople = supplier.get().filter(CastEntityConvert.distinctByKey(ActivityRecord::getPhoneNum)).count();
        logsCountInDay.setTotalPeople(totalPeople);
        countForActivity.setTotalPeople(countForActivity.getTotalPeople() + totalPeople);
        // 消耗积分数
        long consumeScore = supplier.get().filter(r -> r.getConsumeScore() != null).mapToLong(ActivityRecord::getConsumeScore).sum();
        logsCountInDay.setConsumeScore(consumeScore);
        countForActivity.setConsumeScore(countForActivity.getConsumeScore() + consumeScore);
        // 积分下发数
        long prizeScore = supplier.get()
                .filter(ActivityRecord::isAwarded)
                .filter(r -> r.getBill() != null
                        && (PrizeType.CLUB_INTEGRAL.equals(r.getPrizeType()) || PrizeType.CLUB_INTEGRAL_WITH_NUM.equals(r.getPrizeType())))
                .mapToLong(ActivityRecord::getBill).sum();
        logsCountInDay.setPrizeScore(prizeScore);
        countForActivity.setPrizeScore(countForActivity.getPrizeScore() + prizeScore);
        // pv
        countForActivity.setPv(countForActivity.getPv() + logsCountInDay.getPv());
        // vu UV无法去重，暂作相加处理
        countForActivity.setUv(countForActivity.getUv() + logsCountInDay.getUv());
        logsCountRepository.save(logsCountInDay);
        logsCountRepository.save(countForActivity);
    }

    void findActivities() {
        List<ActivityInfo> activityInfos = activityInfoRepository.findAll();
        if (activityInfos == null || activityInfos.size() == 0) {
            log.info("没有活动信息");
            activityInfoMap = new HashMap<>();
        } else {
            Map<String, String> map = new HashMap<>(activityInfos.size());
            for (ActivityInfo activityInfo : activityInfos) {
                map.put(String.valueOf(activityInfo.getId()), activityInfo.getName());
            }
            this.activityInfoMap = map;
        }
    }
}
